<?xml version="1.0"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>在Twisted中使用线程（Using Threads in Twisted）</title>
  </head>

  <body>
    <h1>在Twisted中使用线程（Using Threads in Twisted）</h1>

    <h2>在线程安全的环境下运行程序</h2>

    <p>大部分的Twisted代码都不是线程安全的，比如说由protocol
    （这里应该指的是负责会话逻辑的protocol?）向transport（
    这里是指的Twisted跟Socket通讯的那个transport?）写数据就是非
    线程安全的。因此，我们就要在主循环中调度这些方法。可以通过
     <code class="API">
     twisted.internet.interfaces.IReactorThreads.callFromThread
     </code>函数做到：</p>
<pre class="python">
from twisted.internet import reactor

def notThreadSafe(x):
     """do something that isn't thread-safe"""
     # ...

def threadSafeScheduler():
    """Run in thread-safe manner."""
    reactor.callFromThread(notThreadSafe, 3) # will run 'notThreadSafe(3)'
                                             # in the event loop
</pre>

    <h2>在线程中运行代码</h2>

    <p>有些时候我们想要以线程的方式来运行代码 —— 比如当我们
    的代码使用到了阻塞式API的时候。Twisted通过IReactorThreads API (<code
    class="API">twisted.internet.interfaces.IReactorThreads</code>)
    提供了相应的方法。并且 <code
    class="API">twisted.internet.threads</code>中也提供了一些额外
    的实用的函数来支持这一点。简单说来，这些函数方法允许我们以线程池
    的形式来管理调度我们的代码。</p>

    <p>举个例子，可以通过这样的方法在线程中执行我们的代码：</p>
<pre class="python">
from twisted.internet import reactor

def aSillyBlockingMethod(x):
    import time
    time.sleep(2)
    print x

# run method in thread
reactor.callInThread(aSillyBlockingMethod, "2 seconds have passed")
</pre>

    <h2>实用的工具方法</h2>

    <p> 这些方法并不是<code
    class="API">twisted.internet.reactor</code> API的一部分，而是在
    <code class="API">twisted.internet.threads</code>中实现的。</p>

    <p>如果我们有许多方法需要顺序的在一个线程中执行，这么做：</p>

<pre class="python">
from twisted.internet import threads

def aSillyBlockingMethodOne(x):
    import time
    time.sleep(2)
    print x

def aSillyBlockingMethodTwo(x):
    print x

# run both methods sequentially in a thread
commands = [(aSillyBlockingMethodOne, ["Calling First"], {})]
commands.append((aSillyBlockingMethodTwo, ["And the second"], {}))
threads.callMultipleInThread(commands)
</pre>

    <p>我们想把一个函数放到线程里面执行，而且又想得到他的返回值，可以让
    这个函数返回一个Deferred：</p>
<pre class="python">
from twisted.internet import threads

def doLongCalculation():
    # .... do long calculation here ...
    return 3

def printResult(x):
    print x

# run method in thread and get result as defer.Deferred
d = threads.deferToThread(doLongCalculation)
d.addCallback(printResult)
</pre>

    <p>想在reactor中调用一个函数并且得到他的结果，可以使用
    <code base="twisted.internet.threads" class="API">
    blockingCallFromThread</code>：</p>

<pre class="python">
from twisted.internet import threads, reactor, defer
from twisted.web.client import getPage
from twisted.web.error import Error

def inThread():
    try:
        result = threads.blockingCallFromThread(
            reactor, getPage, "http://twistedmatrix.com/")
    except Error, exc:
        print exc
    else:
        print result
    reactor.callFromThread(reactor.stop)

reactor.callInThread(inThread)
reactor.run()
</pre>

    <p><code>blockingCallFromThread</code> 会返回一个对象或者是抛出
    返回的异常，也可能抛出一个传递给它的异常， 如果说传递给他的是一个
    Deferred,那么返回的就是一个经过callback处理的结果或者是经过errback
    处理的异常（是这样么？）。</p>

    <h2>管理线程池</h2>

    <p>Twisted中的线程池是由 <code
    class="API">twisted.python.threadpool.ThreadPool</code>实现的。</p>

    <p>可以很简单的完成对线程池容量大小的修改：</p>

<pre class="python">
from twisted.internet import reactor

reactor.suggestThreadPoolSize(30)
</pre>

  <p>线程池默认的大小决定于reactor。默认的reactor规定容量的大小在5到10之间。
  需要格外小心的是，在你改变池大小之前，确保你知道这些线程资源的使用情况。
  </p>
  </body>
</html>

